#include <sxFixedTimelineCurveController.h>

Sx::Multimedia::Interface::FixedTimelineCurveController::FixedTimelineCurveController(Viewport* viewport, const std::shared_ptr<Canvas>& canvas, const std::shared_ptr<ScenePickingController>& pickingController, const std::shared_ptr<RendererImplementation>& cameraRenderer, const std::shared_ptr<RendererImplementation>& plotRenderer, const std::shared_ptr<RendererImplementation>& cuboidRenderer, const std::shared_ptr<RendererImplementation>& bezierRenderer) :
	ViewportController(viewport), timeline(nullptr), curveEditor(nullptr) {

	//--------------------------------------------------------------------------
	// Initialize the timeline (VS2010 Limitation on std::make_shared can only
	// accept 10 arguments (since it has "variadic templates").. :(
	//--------------------------------------------------------------------------
	this->timeline = std::shared_ptr<FixedTimelineController>(new FixedTimelineController(viewport, canvas, pickingController, cameraRenderer, plotRenderer, cuboidRenderer, 0, 20, 5, 5, 0, 0, 1.0f));
	this->curveEditor = std::shared_ptr<BezierEditController>(new BezierEditController(viewport, canvas, pickingController, cameraRenderer, plotRenderer, bezierRenderer, 0, 20, 5, 5, 0, 0, 1.0f));
	this->curveEditor->setSnapSpacing(1.0f / 60.0f, 1.0f / 60.0f, 1.0f / 60.0f);
	this->curveEditor->setVariablePointCurve(true);
}

Sx::Multimedia::Interface::FixedTimelineCurveController::~FixedTimelineCurveController() {}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::initialize() {
	if ( this->timeline == nullptr ) {
		std::cerr << "[FixedTimelineCurveController:initialize] Error: Timeline controller not initialized (nullptr)." << std::endl;
		return false;
	}

	if ( this->curveEditor == nullptr ) {
		std::cerr << "[FixedTimelineCurveController:initialize] Error: Curve editor controller not initialized (nullptr)." << std::endl;
		return false;
	}

	this->timeline->initialize();
	this->curveEditor->initialize();
	return true;
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::update(float dt) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->timeline->update(dt);
	this->curveEditor->update(dt);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::render() const {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->timeline->render();
	this->curveEditor->render();
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::resize(int width, int height) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->timeline->resize(width, height);
	this->curveEditor->resize(width, height);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::setInputEnabled(bool enabled) {
	if ( this->timeline == nullptr ) return;
	this->timeline->setInputEnabled(enabled);
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::setDivisions(unsigned int count) {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->setDivisions(count);
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::setCurrentTime(unsigned int time) {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->setCurrentTime(time);
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::incrementTime() {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->incrementTime();
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::decrementTime() {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->decrementTime();
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::setCurrentFrame(unsigned int frame) {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->setCurrentFrame(frame);
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::setEndTime(unsigned int endTime) {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->setEndTime(endTime);
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::setFrameCount(unsigned int frameCount) {
	if ( this->timeline == nullptr ) return false;
	return this->timeline->setFrameCount(frameCount);
}

unsigned int Sx::Multimedia::Interface::FixedTimelineCurveController::getCurrentTime() const {
	if ( this->timeline == nullptr ) return 0u;
	return this->timeline->getCurrentTime();
}

unsigned int Sx::Multimedia::Interface::FixedTimelineCurveController::getStartTime() const {
	if ( this->timeline == nullptr ) return 0u;
	return this->timeline->getStartTime();
}

unsigned int Sx::Multimedia::Interface::FixedTimelineCurveController::getEndTime() const {
	if ( this->timeline == nullptr ) return 0u;
	return this->timeline->getEndTime();
}

unsigned int Sx::Multimedia::Interface::FixedTimelineCurveController::size() const {
	if ( this->timeline == nullptr ) return 0u;
	return this->timeline->size();
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::setReplayable(const std::shared_ptr<Replayable>& replayable) {
	if ( this->timeline == nullptr ) return;
	this->timeline->setReplayable(replayable);
}

bool Sx::Multimedia::Interface::FixedTimelineCurveController::getCurveApproximation(Util::ArrayList<Eigen::Vector3f>& approximationPoints) {
	if ( this->curveEditor == nullptr ) {
		std::cerr << "[FixedTimelineCurveController:getCurveApproximation] Error: Curve editor has not been initialized (nullptr)." << std::endl;
		return false;
	}

	return this->curveEditor->getCurveApproximation(approximationPoints);
}

long Sx::Multimedia::Interface::FixedTimelineCurveController::getEndPointSnapPositionX(bool index) const {
	if ( this->curveEditor == nullptr ) {
		std::cerr << "[FixedTimelineCurveController:getEndPointSnapPositionX] Error: Curve editor has not been initialized (nullptr)." << std::endl;
		return 0u;
	}

	return this->curveEditor->getEndPointSnapPositionX(index);
}

long Sx::Multimedia::Interface::FixedTimelineCurveController::getEndPointSnapPositionY(bool index) const {
	if ( this->curveEditor == nullptr ) {
		std::cerr << "[FixedTimelineCurveController:getEndPointSnapPositionY] Error: Curve editor has not been initialized (nullptr)." << std::endl;
		return 0u;
	}

	return this->curveEditor->getEndPointSnapPositionY(index);
}

long Sx::Multimedia::Interface::FixedTimelineCurveController::getEndPointSnapPositionZ(bool index) const {
	if ( this->curveEditor == nullptr ) {
		std::cerr << "[FixedTimelineCurveController:getEndPointSnapPositionZ] Error: Curve editor has not been initialized (nullptr)." << std::endl;
		return 0u;
	}

	return this->curveEditor->getEndPointSnapPositionZ(index);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mousePressEvent(int x, int y, MouseButton button, ModifierKey modifierKey) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;
	this->setMousePressPosition(x, y);

	this->curveEditor->mousePressEvent(x, y, button, modifierKey);
	this->timeline->mousePressEvent(x, y, button, modifierKey);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mouseReleaseEvent(int x, int y, MouseButton button, ModifierKey modifierKey) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;
	this->setMouseReleasePosition(x, y);

	this->curveEditor->mouseReleaseEvent(x, y, button, modifierKey);
	this->timeline->mouseReleaseEvent(x, y, button, modifierKey);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mouseClickEvent(int x, int y, MouseButton button, ModifierKey modifierKey) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->curveEditor->mouseClickEvent(x, y, button, modifierKey);
	this->timeline->mouseClickEvent(x, y, button, modifierKey);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mouseMoveEvent(int x, int y, MouseButton button, ModifierKey modifierKey) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;
	this->setMouseCurrentPosition(x, y);
	this->updateMousePositionDifference();

	//--------------------------------------------------------------------------
	// Update the difference positions of the two internal controllers.
	//--------------------------------------------------------------------------
	this->timeline->setMousePositionDifference(this->positionDifference);
	this->timeline->setMouseCurrentPosition(x, y);
	this->curveEditor->setMousePositionDifference(this->positionDifference);
	this->curveEditor->setMouseCurrentPosition(x, y);

	if ( this->timeline->isInEdit() == false ) this->curveEditor->mouseMoveEvent(x, y, button, modifierKey);
	if ( this->curveEditor->isInEdit() == false ) this->timeline->mouseMoveEvent(x, y, button, modifierKey);

	this->updateMouseLastPosition();
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mouseWheelEvent(int delta) {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->curveEditor->mouseWheelEvent(delta);
	this->timeline->mouseWheelEvent(delta);
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mouseEnterEvent() {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->curveEditor->mouseEnterEvent();
	this->timeline->mouseEnterEvent();
}

void Sx::Multimedia::Interface::FixedTimelineCurveController::mouseExitEvent() {
	if ( this->timeline == nullptr || this->curveEditor == nullptr ) return;

	this->curveEditor->mouseExitEvent();
	this->timeline->mouseExitEvent();
}
